package br.edu.ufcg.msnlab2.grupo07;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import junit.framework.TestCase;
import mathExpr.parser.javacc.ParseException;
import br.edu.ufcg.msnlab2.InvalidFunctionException;
import br.edu.ufcg.msnlab2.misc.Function;
import br.edu.ufcg.msnlab2.misc.FunctionImpl;


public class FunctionImplTest extends TestCase{
	
	/**
	 * This method verifies if the computation of a function value in a certain
	 * point is being done correctly. Here functions with only one variable
	 * are considered.
	 * @throws ParseException Exception thrown if an invalid function expression is being parsed
	 * @throws InvalidFunctionException 
	 */
	public void testCalculateFunctionValueInOnePointForOneVariable() throws ParseException, InvalidFunctionException{
		//Configuring expression
		Function function = new FunctionImpl("x^2+x*3");
		
		//Collection of points
		Map<String, List<Double>> sampledPoints = new HashMap<String, List<Double>>();
		sampledPoints.put("x", new ArrayList<Double>());
		sampledPoints.get("x").add(3.0d);
		sampledPoints.get("x").add(5.5d);
		
		//Testing results
		double result = function.evaluate(sampledPoints, 0);
		assertNotNull(result);
		assertEquals(result, 18d);
		
		result = function.evaluate(sampledPoints,  1);
		assertNotNull(result);
		assertEquals(result, 46.75d);
		
		//Testing with an invalid index
		function = new FunctionImpl("sin(x^(3*x+1))");
		
		try{
			function.evaluate(sampledPoints, 2);
			fail("Invalid points index!");
		}catch(IndexOutOfBoundsException e){
		}
		
		try{
			function.evaluate(sampledPoints, 100);
			fail("Invalid points index!");
		}catch(IndexOutOfBoundsException e){
		}
		
		try{
			function.evaluate(sampledPoints, -2);
			fail("Negative points index!");
		}catch(RuntimeException e){
		}
		
		//Invalid set of sampled points
		try{
			function.evaluate(null, 1);
			fail("Negative points index!");
		}catch(RuntimeException e){
		}
		
		try{
			function.evaluate(new HashMap<String, List<Double>>(), 1);
			fail("Negative points index!");
		}catch(RuntimeException e){
		}
		
		sampledPoints = new HashMap<String, List<Double>>();
		ArrayList<Double> points = new ArrayList<Double>();
		points.add(10d);
		sampledPoints.put("h", points);
		try{
			function.evaluate(sampledPoints, 1);
			fail("Negative points index!");
		}catch(RuntimeException e){
		}
		
		sampledPoints = new HashMap<String, List<Double>>();
		sampledPoints.put("h", new ArrayList<Double>());
		try{
			function.evaluate(sampledPoints, 1);
			fail("Negative points index!");
		}catch(RuntimeException e){
		}
		
		sampledPoints = new HashMap<String, List<Double>>();
		sampledPoints.put("x", new ArrayList<Double>());
		try{
			function.evaluate(sampledPoints, 1);
			fail("Negative points index!");
		}catch(RuntimeException e){
		}
	}
	
	/**
	 * This method verifies if the computation of a function value in a certain
	 * point is being done correctly. Here functions with two or more variables
	 * are considered.
	 * @throws ParseException Exception thrown if an invalid function expression is being parsed
	 * @throws InvalidFunctionException 
	 */
	public void testCalculateFunctionValueInOnePointForMoreThanOneVariable() throws ParseException, InvalidFunctionException{
		//Configuring expression
		Function function = new FunctionImpl("x^2+10*a");
		
		//Collection of points
		Map<String, List<Double>> sampledPoints = new HashMap<String, List<Double>>();
		sampledPoints.put("x", new ArrayList<Double>());
		sampledPoints.get("x").add(10.0d);
		sampledPoints.get("x").add(9999999999999d);
		sampledPoints.put("a", new ArrayList<Double>());
		sampledPoints.get("a").add(1.0d);
		sampledPoints.get("a").add(2d);
		
		//Testing results
		double result = function.evaluate(sampledPoints, 0);
		assertNotNull(result);
		assertEquals(result, 110d);
		
		result =  function.evaluate(sampledPoints, 1);
		assertNotNull(result);
		assertEquals(result, 9.999999999998E25);
		
		//Three variables
		function = new FunctionImpl("2*x+10^a+y");
		
		sampledPoints = new HashMap<String, List<Double>>();
		sampledPoints.put("x", new ArrayList<Double>());
		sampledPoints.get("x").add(55.7d);
		sampledPoints.put("a", new ArrayList<Double>());
		sampledPoints.get("a").add(100.0d);
		sampledPoints.put("y", new ArrayList<Double>());
		sampledPoints.get("y").add(0.123d);
		
		//Testing results
		result = function.evaluate(sampledPoints, 0);
		assertNotNull(result);
		assertEquals(result, 1.0E+100);
		
		//Testing with an invalid index
		function = new FunctionImpl("x^2+a");
		
		try{
			function.evaluate(sampledPoints, 2);
			fail("Invalid points index!");
		}catch(IndexOutOfBoundsException e){
		}
		
		try{
			function.evaluate(sampledPoints, 100);
			fail("Invalid points index!");
		}catch(IndexOutOfBoundsException e){
		}
		
		try{
			function.evaluate(sampledPoints, -2);
			fail("Negative points index!");
		}catch(RuntimeException e){
		}
		
		//Invalid set of sampled points
		try{
			function.evaluate(null, 1);
			fail("Negative points index!");
		}catch(RuntimeException e){
		}
		
		try{
			function.evaluate(new HashMap<String, List<Double>>(),  1);
			fail("Negative points index!");
		}catch(RuntimeException e){
		}
		
		sampledPoints = new HashMap<String, List<Double>>();
		ArrayList<Double> points = new ArrayList<Double>();
		points.add(10d);
		sampledPoints.put("h", points);
		try{
			function.evaluate(sampledPoints,  1);
			fail("Negative points index!");
		}catch(RuntimeException e){
		}
		
		sampledPoints = new HashMap<String, List<Double>>();
		sampledPoints.put("h", new ArrayList<Double>());
		try{
			function.evaluate(sampledPoints, 1);
			fail("Negative points index!");
		}catch(RuntimeException e){
		}
		
		sampledPoints = new HashMap<String, List<Double>>();
		sampledPoints.put("x", new ArrayList<Double>());
		try{
			function.evaluate(sampledPoints, 1);
			fail("Negative points index!");
		}catch(RuntimeException e){
		}
	}

}
